// Cell names have been changed in this file by netl_namemap on Mon Jan  3 04:00:11 UTC 2022
//////////////////////////////////////////////////////////////////////////////
//
//  pcs_raw_arbt.v
//
//  Raw PCS Arbiter module (with round-robin priority allocation)
//
//  Original Author: Ameer Youssef
//  Current Owner:   Dom Spagnuolo
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015 Synopsys, Inc.  All rights reserved.
//
// SYNOPSYS CONFIDENTIAL - This is an unpublished, proprietary work of
// Synopsys, Inc., and is fully protected under copyright and trade secret
// laws.  You may not view, use, disclose, copy, or distribute this file or
// any information contained herein except pursuant to a valid written
// license agreement. It may not be used, reproduced, or disclosed to others
// except in accordance with the terms and conditions of that agreement.
//
//////////////////////////////////////////////////////////////////////////////
//
//    Perforce Information
//    $Author: spagnuol $
//    $File: //dwh/up16/main/dev/pcs_raw/dig/rtl/pcs_raw_arbt.v $
//    $DateTime: 2015/12/22 06:27:08 $
//    $Revision: #21 $
//
//////////////////////////////////////////////////////////////////////////////
`include "dwc_e12mp_phy_x4_ns_cr_macros.v"
`include "dwc_e12mp_phy_x4_ns_macros.v"
`include "dwc_e12mp_phy_x4_ns_pcs_raw_macros.v"

`timescale 1ns/10fs
module dwc_e12mp_phy_x4_ns_pcs_raw_arbt (
// Clock and Reset
input  wire              cr_clk,
input  wire              cr_rst,

// CR input interfaces
input  wire [16-1:0]     cr_req,
input  wire [16*16-1:0]  cr_addr,
input  wire [16*16-1:0]  cr_wr_data,
input  wire [16-1:0]     cr_wr_en,
input  wire [16-1:0]     cr_rd_en,
input  wire [16-1:0]     cr_op_xtnd,
output wire [16-1:0]     cr_ack,
output wire [16*16-1:0]  cr_rd_data,
`ifdef DWC_E12MP_X4NS_SRAM_SUPPORT
// Mantis 7114 - if this arbiter is using sram access then extend the read operations
input  wire              sram_timing_en,
`endif

// CR output interface
output wire [15:0]       cr_arbt_addr,
output wire [15:0]       cr_arbt_wr_data,
output reg               cr_arbt_wr_en,
output wire              cr_arbt_rd_en,
input  wire [15:0]       cr_arbt_rd_data
);

// -------------------------
// Registers and nets
// -------------------------
reg  [3:0]     cr_arbt_sel_int;
reg  [3:0]     cr_arbt_sel_s;
wire [3:0]     cr_arbt_sel;
wire           cr_arbt_ack;
reg  [3:0]     hp_index;

reg  [3:0]     cr_arbt_sel_d1;
reg            cr_arbt_ack_d1;
reg            cr_arbt_ack_d2;
wire           cr_arbt_wr_en_int;
wire           cr_arbt_rd_en_int;  
reg  [15:0]    cr_arbt_wr_data_int;
reg  [15:0]    cr_arbt_addr_int;
reg  [15:0]    cr_arbt_wr_data_int_d1;
reg            cr_arbt_wr_en_int_d1;
reg            cr_arbt_rd_en_int_d1;
reg  [15:0]    cr_ack_int_d1;
wire           cr_arbt_op_xtnd; 
wire [15:0]    cr_ack_int;
wire           cr_access_det;
// Mantis 7117 - Fix LINT issues in cr_access_det_d and cr_arbt_addr_int_d1
reg  [3:0]     cr_access_det_d;
reg            cr_access_in_prog;

wire [3:0] hp_index_p1  = hp_index[3:0] + 4'd1;
wire [3:0] hp_index_p2  = hp_index[3:0] + 4'd2;
wire [3:0] hp_index_p3  = hp_index[3:0] + 4'd3;
wire [3:0] hp_index_p4  = hp_index[3:0] + 4'd4;
wire [3:0] hp_index_p5  = hp_index[3:0] + 4'd5;
wire [3:0] hp_index_p6  = hp_index[3:0] + 4'd6;
wire [3:0] hp_index_p7  = hp_index[3:0] + 4'd7;
wire [3:0] hp_index_p8  = hp_index[3:0] + 4'd8;
wire [3:0] hp_index_p9  = hp_index[3:0] + 4'd9;
wire [3:0] hp_index_p10 = hp_index[3:0] + 4'd10;
wire [3:0] hp_index_p11 = hp_index[3:0] + 4'd11;
wire [3:0] hp_index_p12 = hp_index[3:0] + 4'd12;
wire [3:0] hp_index_p13 = hp_index[3:0] + 4'd13;
wire [3:0] hp_index_p14 = hp_index[3:0] + 4'd14;
wire [3:0] hp_index_p15 = hp_index[3:0] + 4'd15;


// Advance hp_index by 1 when previous request is ack'ed
// (enforces round-robin selection)
// Keep the address and data stable for an extra cycle in FPGA mode.
always @(posedge cr_rst or posedge cr_clk) begin
  if (cr_rst)
    hp_index <= 4'd0;
`ifdef DWC_FPGA_MODE
  else if (cr_arbt_ack_d1)
`else
  else if (cr_arbt_ack)
`endif
    hp_index <= cr_arbt_sel + 4'd1;   
end 

// -----------------------------------
// Find next request in priority order
// -----------------------------------
always @* begin 
  cr_arbt_sel_int = cr_req[hp_index    ] ? hp_index     :
                    cr_req[hp_index_p1 ] ? hp_index_p1  :
                    cr_req[hp_index_p2 ] ? hp_index_p2  :
                    cr_req[hp_index_p3 ] ? hp_index_p3  :
                    cr_req[hp_index_p4 ] ? hp_index_p4  :
                    cr_req[hp_index_p5 ] ? hp_index_p5  :
                    cr_req[hp_index_p6 ] ? hp_index_p6  :
                    cr_req[hp_index_p7 ] ? hp_index_p7  :
                    cr_req[hp_index_p8 ] ? hp_index_p8  :
                    cr_req[hp_index_p9 ] ? hp_index_p9  :
                    cr_req[hp_index_p10] ? hp_index_p10 :
                    cr_req[hp_index_p11] ? hp_index_p11 :
                    cr_req[hp_index_p12] ? hp_index_p12 :
                    cr_req[hp_index_p13] ? hp_index_p13 :
                    cr_req[hp_index_p14] ? hp_index_p14 :
                    cr_req[hp_index_p15] ? hp_index_p15 :
                                           hp_index;
end

// Do not update the cr_arbt_sel for the duration of a cr access.
assign cr_arbt_sel = cr_access_in_prog? cr_arbt_sel_s : cr_arbt_sel_int;

// --------------------------------------------------
// Set internal arbiter signals based on cr_arbt_sel
// --------------------------------------------------
assign cr_arbt_wr_en_int = cr_wr_en[cr_arbt_sel];
assign cr_arbt_rd_en_int = cr_rd_en[cr_arbt_sel];
assign cr_arbt_op_xtnd = cr_op_xtnd[cr_arbt_sel];

always @* begin
  case (cr_arbt_sel)
    4'd1 :  cr_arbt_addr_int = cr_addr[1  * 16 + 15 : 1  * 16];
    4'd2 :  cr_arbt_addr_int = cr_addr[2  * 16 + 15 : 2  * 16];
    4'd3 :  cr_arbt_addr_int = cr_addr[3  * 16 + 15 : 3  * 16];
    4'd4 :  cr_arbt_addr_int = cr_addr[4  * 16 + 15 : 4  * 16];
    4'd5 :  cr_arbt_addr_int = cr_addr[5  * 16 + 15 : 5  * 16];
    4'd6 :  cr_arbt_addr_int = cr_addr[6  * 16 + 15 : 6  * 16];
    4'd7 :  cr_arbt_addr_int = cr_addr[7  * 16 + 15 : 7  * 16];
    4'd8 :  cr_arbt_addr_int = cr_addr[8  * 16 + 15 : 8  * 16];
    4'd9 :  cr_arbt_addr_int = cr_addr[9  * 16 + 15 : 9  * 16];
    4'd10:  cr_arbt_addr_int = cr_addr[10 * 16 + 15 : 10 * 16];
    4'd11:  cr_arbt_addr_int = cr_addr[11 * 16 + 15 : 11 * 16];
    4'd12:  cr_arbt_addr_int = cr_addr[12 * 16 + 15 : 12 * 16];
    4'd13:  cr_arbt_addr_int = cr_addr[13 * 16 + 15 : 13 * 16];
    4'd14:  cr_arbt_addr_int = cr_addr[14 * 16 + 15 : 14 * 16];
    4'd15:  cr_arbt_addr_int = cr_addr[15 * 16 + 15 : 15 * 16];
  default:  cr_arbt_addr_int = cr_addr[0  * 16 + 15 : 0  * 16];
  endcase
end

always @* begin
  case (cr_arbt_sel)
    4'd1 :  cr_arbt_wr_data_int = cr_wr_data[1  * 16 + 15 : 1  * 16];
    4'd2 :  cr_arbt_wr_data_int = cr_wr_data[2  * 16 + 15 : 2  * 16];
    4'd3 :  cr_arbt_wr_data_int = cr_wr_data[3  * 16 + 15 : 3  * 16];
    4'd4 :  cr_arbt_wr_data_int = cr_wr_data[4  * 16 + 15 : 4  * 16];
    4'd5 :  cr_arbt_wr_data_int = cr_wr_data[5  * 16 + 15 : 5  * 16];
    4'd6 :  cr_arbt_wr_data_int = cr_wr_data[6  * 16 + 15 : 6  * 16];
    4'd7 :  cr_arbt_wr_data_int = cr_wr_data[7  * 16 + 15 : 7  * 16];
    4'd8 :  cr_arbt_wr_data_int = cr_wr_data[8  * 16 + 15 : 8  * 16];
    4'd9 :  cr_arbt_wr_data_int = cr_wr_data[9  * 16 + 15 : 9  * 16];
    4'd10:  cr_arbt_wr_data_int = cr_wr_data[10 * 16 + 15 : 10 * 16];
    4'd11:  cr_arbt_wr_data_int = cr_wr_data[11 * 16 + 15 : 11 * 16];
    4'd12:  cr_arbt_wr_data_int = cr_wr_data[12 * 16 + 15 : 12 * 16];
    4'd13:  cr_arbt_wr_data_int = cr_wr_data[13 * 16 + 15 : 13 * 16];
    4'd14:  cr_arbt_wr_data_int = cr_wr_data[14 * 16 + 15 : 14 * 16];
    4'd15:  cr_arbt_wr_data_int = cr_wr_data[15 * 16 + 15 : 15 * 16];
  default:  cr_arbt_wr_data_int = cr_wr_data[0  * 16 + 15 : 0  * 16];
  endcase
end

// delay internal signals by 1 cycle
always @(posedge cr_clk or posedge cr_rst) begin
  if (cr_rst) begin
    cr_arbt_sel_d1         <= 4'd0;
    cr_arbt_ack_d1         <= 1'b0;
    cr_arbt_ack_d2         <= 1'b0;
    cr_arbt_wr_data_int_d1 <= 16'd0;
    cr_arbt_wr_en_int_d1   <= 1'b0;
    cr_arbt_rd_en_int_d1   <= 1'b0;
    cr_ack_int_d1          <= 16'd0;
  end
  else begin
    cr_arbt_sel_d1         <= cr_arbt_sel;
    cr_arbt_ack_d1         <= cr_arbt_ack;
    cr_arbt_ack_d2         <= cr_arbt_ack_d1;
    cr_arbt_wr_data_int_d1 <= cr_arbt_wr_data_int;
    cr_arbt_wr_en_int_d1   <= cr_arbt_wr_en_int;
    cr_arbt_rd_en_int_d1   <= cr_arbt_rd_en_int;
    cr_ack_int_d1          <= cr_ack_int;
  end
end
// The ack is generated in the same cycle as the rd_en or wr_en.
// Exceptions:
//    - Ack should be reset if doing read and staying on the same select
//    - It's generation should be delayed by a cycle for extended operations
`ifdef DWC_FPGA_MODE
  assign cr_arbt_ack = cr_arbt_ack_d1 ? 1'b0 :
                       (cr_arbt_wr_en_int ? cr_access_det_d[2] :
                         (cr_arbt_rd_en_int ? (cr_arbt_op_xtnd ? cr_access_det_d[2] : cr_access_det_d[1]) : 1'b0));
`else
  assign cr_arbt_ack = (cr_arbt_ack_d1 & cr_arbt_rd_en_int & (cr_arbt_sel == cr_arbt_sel_d1)) ? 1'b0 :
                       cr_arbt_wr_en_int ? (cr_arbt_op_xtnd ? {cr_access_det_d[3:0],cr_access_det} == 5'b10000
                                                            : cr_access_det) :
`ifdef DWC_E12MP_X4NS_SRAM_SUPPORT
                       cr_arbt_rd_en_int ? ((cr_arbt_op_xtnd | sram_timing_en) ?
`else
                       cr_arbt_rd_en_int ? (cr_arbt_op_xtnd ?
`endif
                                            {cr_access_det_d[0],cr_access_det} == 2'b10 :
                                            cr_access_det) : 1'b0;
`endif

// Detect an access request on CR interface
always @(posedge cr_clk or posedge cr_rst) begin
  if (cr_rst) begin
    cr_access_det_d <= 4'd0;
    cr_arbt_wr_en <= 1'b0; 
  end
  else begin
    cr_access_det_d[3:0] <= {cr_access_det_d[2:0], cr_access_det};
    `ifdef DWC_FPGA_MODE
      cr_arbt_wr_en <= cr_arbt_wr_en_int & (cr_access_det_d[0] | cr_access_det_d[1]);
    `else
      cr_arbt_wr_en <= cr_arbt_wr_en_int &
                       (cr_arbt_op_xtnd ? {cr_access_det_d[1:0],cr_access_det} == 3'b100
                                        : 1'b1);
    `endif
  end
end 
    
// New access detected if:
//   FPGA
//   - wr_en or rd_en posedge
//   - wr_en or rd_en asserted and act asserted in previous cycle
//   ASIC
//   - wr_en or rd_en posedge
//   - wr_en is asserted and ack asserted in previous cycle (i.e. this is a new wr_en)
//   - rd_en is asserted and ack asserted in previous cycle and not on same select (i.e. new rd_en if new select)
//   - rd_en is asserted and ack asserted in 2nd previous cycle (i.e. definitely new rd_en)
assign cr_access_det = (~cr_arbt_wr_en_int_d1 & cr_arbt_wr_en_int) |
                       (~cr_arbt_rd_en_int_d1 & cr_arbt_rd_en_int) |
                       `ifdef DWC_FPGA_MODE
                       ((cr_arbt_wr_en_int | cr_arbt_rd_en_int) & cr_arbt_ack_d2);
                       `else
                       (cr_arbt_wr_en_int & cr_arbt_ack_d1) |
                       (cr_arbt_rd_en_int & cr_arbt_ack_d1 & ~(cr_arbt_sel == cr_arbt_sel_d1)) |
                       (cr_arbt_rd_en_int & cr_arbt_ack_d2 & ~cr_arbt_ack_d1);
                       `endif

// CR access in progress flag
// cr_arbt_ack takes priority to ensure cr_access_in_prog is not set for same cycle acks.
always @(posedge cr_clk or posedge cr_rst) begin
  if (cr_rst) begin
    cr_access_in_prog <= 1'b0;
  end
  else begin
    `ifdef DWC_FPGA_MODE
    if (cr_arbt_ack_d1 == 1'b1)
    `else
    if (cr_arbt_ack == 1'b1)
    `endif
      cr_access_in_prog <= 1'b0;
    else if (cr_access_det == 1'b1)
      cr_access_in_prog <= 1'b1;
  end
end

always @(posedge cr_clk or posedge cr_rst) begin
  if (cr_rst) begin
    cr_arbt_sel_s <= 4'd0;
  end
  else begin
    if (!cr_access_in_prog)  
      cr_arbt_sel_s <= cr_arbt_sel_int;
  end
end

// -------------------------------------------
// Arbiter outputs to request interfaces
// -------------------------------------------
genvar i;
generate for (i=0; i<16; i=i+1) begin: gen_arbt_ack
  // Assign the corresponding internal ack
  assign cr_ack_int[i] = cr_arbt_ack & (cr_arbt_sel == i);
  // Delay the ack in the case of read
  // In FPGA mode do not delay it as the cr_ack_int is already delayed
  // In ASIC cr_ack_int is not delayed to maximize throughput of arbiter
  // this is because even though reads take two cycles but they can be
  // pipelined in back-to-back cycles
  `ifdef DWC_FPGA_MODE   
    assign cr_ack[i] = cr_ack_int[i];
  `else
    assign cr_ack[i] = cr_rd_en[i] ? cr_ack_int_d1[i] : cr_ack_int[i];
  `endif
end
endgenerate

assign cr_rd_data = {16{cr_arbt_rd_data}};

// -------------------------------------------
// Arbiter outputs to common CREG bus
// -------------------------------------------

// The address goes through an additional flop stage after
// decoding into the 32 one-hot cr_sel bank signals, so it
// should not be flopped here.
assign cr_arbt_addr    = cr_arbt_addr_int;

// wr_data, wr_en and rd_en should be flopped to align with
// the flopped cr_sel signals.
assign cr_arbt_wr_data = cr_arbt_wr_data_int_d1;
assign cr_arbt_rd_en   = cr_arbt_rd_en_int_d1;

endmodule
